#include <pthread.h>
#include <vector>
#include <iostream>
#include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>

#include "BrickServer.h"

#include "LogicServerManager.h"
#include "ProtoSockBase.h"
#include "base.h"

using namespace std;

BrickServer::BrickServer()
{
	pthread_mutex_init(&client_mutex, NULL);
}

int BrickServer::CreateServer()
{
	Socket * server = new SocketServer;

	int fd = server->CreateSock("*", 18888);

	if (-1 == fd)
	{
		cerr << "创建服务器失败" << endl;
		return 1;
	}

	//设置线程熟悉
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS);
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

	while (1)
	{
		int connfd = server->Accept();

		pthread_t tid;
		stThreadParam  * param = new stThreadParam;
		param->pthis = this;
		param->fd = connfd;

		//创建线程
		if (pthread_create(&tid, &attr, BrickServer::ProcessConnect, (void *)param))
		{
			cout << "create RecvFileThread failed" << endl;
			continue;
		}

		pthread_attr_destroy(&attr);
	}

	return 0;
}

void * BrickServer::ProcessConnect(void * arg)
{
	stThreadParam * param = (stThreadParam *)arg;

	BrickServer * pthis = param->pthis;

	unsigned fd = param->fd;
	cout << "连接套接字的描述符是:" << fd << endl;
	ProtoSockBase::PrintPeerName(fd);

	//设置连接套接字非阻塞
	fcntl(fd, F_SETFL, O_NONBLOCK);
	
	//使用epoll，设置事件
    epoll_event event;
	event.events = EPOLLIN | EPOLLET;
	event.data.fd = fd;

     //将连接套接字放入事件中
     //多线程处理
	Epoll poll;
	int ret = poll.AddEpollEvent(fd, &event);

	if (ret)
	{
		cerr << "add fd[" << fd << "] to event failed, reason:" << strerror(errno) << endl;
		return (void*)1;
	}

	//共享变量
	//produce race conditon
	pthread_mutex_lock(&pthis->client_mutex);
	LogicServerManager::GetInstance()->AddNewConnect(fd);   //添加客户端到连接队列中
	pthread_mutex_unlock(&pthis->client_mutex);

	epoll_event pevent[MAX_SIZE];

	while (1)
	{
		int ret = poll.WaitEvent(pevent);

		if (-1 == ret)
		{
			cerr << "epoll有错误产生，错误原因:" <<strerror(errno)<< endl;
			continue;
		}

		for (int i = 0; i < ret; ++i)
		{
			//ready to get all standby epoll event
			//poll are same, so, we check fd
			if (pevent[i].data.fd == fd)
			{
				cout<<"套接字描述符读就绪:"<<fd<<endl;
				//ready to recv msg	
				//打算调整为一次性把消息都读取出来，那么，读取出来之后如何处理多个消息呢？
				//ProtoSockBase不应涉及具体的逻辑处理，只负责提取消息，得到消息集合
				bool isempty = true;
				vector<Message *> msglist;

				int ret = ProtoSockBase::ReceiveProto(fd, msglist);

				if (ret == sock_close)
				{
					//客户端异常中端
					pthread_mutex_lock(&pthis->client_mutex);
					LogicServerManager::GetInstance()->RemoveConnect(fd);   //删除断开的客户端
					pthread_mutex_unlock(&pthis->client_mutex);

                    cout<<"客户端异常关闭"<<endl;
                    ProtoSockBase::PrintPeerName(fd);

                    //关闭对应的连接套接字
					close(fd);

					//该线程运行结束
					//结束时，要释放资源
					delete param;
					return (void*)0;
				}
				else if (ret)
				{
                    switch(ret)
                    {
                        case wrong_type_msg : cerr<<"报文类型错误"<<endl; break;
                        case data_error_msg : cerr<<"消息数据错误，缺少必填字段"<<endl; break;
                    }
				}

				//响应消息非空
				for (int i = 0; i < msglist.size(); ++i)
				{
					//调用消息处理函数
					cout<<"收到新消息的请求，协议类型是:"<<msglist[i]->GetTypeName()<<endl;
					int * param = new int;
					*param = fd;
					LogicServerManager::GetInstance()->OnMessage(msglist[i], param);
				}
			}
		}
	}

	//结束时，要释放资源
	delete param;

	return (void*)0;
}

int main()
{
	BrickServer server;

	server.CreateServer();

	return 0;
}
